#include "iic.h"
#include "delay.h" // 需要你有delay_us函数

#define IIC_SCL(iic) ((iic)->scl_pin)
#define IIC_SDA(iic) ((iic)->sda_pin)

#include "iic.h"
#include "delay.h" // 需要你有 delay_us 函数

// 内联基础引脚操作
static inline void scl_high(soft_iic_t *iic) { pin_set(iic->scl_pin, 1); }
static inline void scl_low(soft_iic_t *iic) { pin_set(iic->scl_pin, 0); }
static inline void sda_high(soft_iic_t *iic) { pin_set(iic->sda_pin, 1); }
static inline void sda_low(soft_iic_t *iic) { pin_set(iic->sda_pin, 0); }
static inline uint8_t sda_read(soft_iic_t *iic) { return pin_get(iic->sda_pin); }
static inline void iic_delay(soft_iic_t *iic) { delay_us(iic->delay_us); }

// SCL/SDA输出输入模式切换
static void sda_out(soft_iic_t *iic) { pin_mode(iic->sda_pin, PIN_MODE_OUTPUT); }
static void sda_in(soft_iic_t *iic) { pin_mode(iic->sda_pin, PIN_MODE_INPUT); }
static void scl_out(soft_iic_t *iic) { pin_mode(iic->scl_pin, PIN_MODE_OUTPUT); }



/* 初始化IIC结构体 */
void iic_init(soft_iic_t *iic, uint32_t scl_pin, uint32_t sda_pin, uint8_t delay_us)
{
    iic->scl_pin = scl_pin;
    iic->sda_pin = sda_pin;
    iic->delay_us = delay_us;
    scl_out(iic);
    sda_out(iic);
    scl_high(iic);
    sda_high(iic);
}

/* 产生IIC起始信号 */
void iic_start(soft_iic_t *iic)
{
    sda_out(iic);
    sda_high(iic);
    scl_high(iic);
    iic_delay(iic);
    sda_low(iic);
    iic_delay(iic);
    scl_low(iic);
    iic_delay(iic);
}

/* 产生IIC停止信号 */
void iic_stop(soft_iic_t *iic)
{
    sda_out(iic);
    scl_low(iic);
    sda_low(iic);
    iic_delay(iic);
    scl_high(iic);
    iic_delay(iic);
    sda_high(iic);
    iic_delay(iic);
}

/* 等待应答，返回1=无应答，0=有应答 */
uint8_t iic_wait_ack(soft_iic_t *iic)
{
    uint8_t t = 0;
    sda_in(iic);
    sda_high(iic);
    iic_delay(iic);
    scl_high(iic);
    iic_delay(iic);
    while (sda_read(iic))
    {
        t++;
        if (t > 250)
        {
            iic_stop(iic);
            return 1;
        }
    }
    scl_low(iic);
    return 0;
}

/* 产生ACK应答 */
void iic_ack(soft_iic_t *iic)
{
    scl_low(iic);
    sda_out(iic);
    sda_low(iic);
    iic_delay(iic);
    scl_high(iic);
    iic_delay(iic);
    scl_low(iic);
}

/* 产生NACK应答 */
void iic_nack(soft_iic_t *iic)
{
    scl_low(iic);
    sda_out(iic);
    sda_high(iic);
    iic_delay(iic);
    scl_high(iic);
    iic_delay(iic);
    scl_low(iic);
}

/* 发送一个字节 */
void iic_send_byte(soft_iic_t *iic, uint8_t byte)
{
    uint8_t t;
    sda_out(iic);
    scl_low(iic);
    for (t = 0; t < 8; t++)
    {
        if (byte & 0x80)
            sda_high(iic);
        else
            sda_low(iic);
        byte <<= 1;
        iic_delay(iic);
        scl_high(iic);
        iic_delay(iic);
        scl_low(iic);
        iic_delay(iic);
    }
}

/* 读取一个字节 */
uint8_t iic_read_byte(soft_iic_t *iic, uint8_t ack)
{
    uint8_t i, receive = 0;
    sda_in(iic);
    for (i = 0; i < 8; i++)
    {
        scl_low(iic);
        iic_delay(iic);
        scl_high(iic);
        receive <<= 1;
        if (sda_read(iic))
            receive++;
        iic_delay(iic);
    }
    scl_low(iic);
    if (ack)
        iic_ack(iic);
    else
        iic_nack(iic);
    return receive;
}

/* 写寄存器（常用） */
uint8_t iic_write_reg(soft_iic_t *iic, uint8_t dev_addr, uint8_t reg, uint8_t data)
{
    iic_start(iic);
    iic_send_byte(iic, dev_addr << 1 | 0); // 写
    if (iic_wait_ack(iic))
    {
        iic_stop(iic);
        return 1;
    }
    iic_send_byte(iic, reg);
    if (iic_wait_ack(iic))
    {
        iic_stop(iic);
        return 2;
    }
    iic_send_byte(iic, data);
    if (iic_wait_ack(iic))
    {
        iic_stop(iic);
        return 3;
    }
    iic_stop(iic);
    return 0;
}

/* 读寄存器（常用） */
uint8_t iic_read_reg(soft_iic_t *iic, uint8_t dev_addr, uint8_t reg, uint8_t *data)
{
    iic_start(iic);
    iic_send_byte(iic, dev_addr << 1 | 0); // 写
    if (iic_wait_ack(iic))
    {
        iic_stop(iic);
        return 1;
    }
    iic_send_byte(iic, reg);
    if (iic_wait_ack(iic))
    {
        iic_stop(iic);
        return 2;
    }
    iic_start(iic);
    iic_send_byte(iic, dev_addr << 1 | 1); // 读
    if (iic_wait_ack(iic))
    {
        iic_stop(iic);
        return 3;
    }
    *data = iic_read_byte(iic, 0); // 读1字节，NACK
    iic_stop(iic);
    return 0;
}